﻿#define _CRT_SECURE_NO_WARNINGS // 必须放在所有头文件之前
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QMessageBox>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <App/Application.h>
#include <Base/ConsoleObserver.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
#include <Gui/Application.h>
#include <qdir.h>
#   define FC_OS_WIN32
// OpenGL 绘制区域
class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
public:
    OpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {}

protected:
    void initializeGL() override {
        initializeOpenGLFunctions();
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 背景色
    }

    void paintGL() override {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // 绘制一个彩色立方体
        glBegin(GL_QUADS);
            // 前面 (红色)
            glColor3f(1.0f, 0.0f, 0.0f);
            glVertex3f(-0.5f, -0.5f, 0.5f);
            glVertex3f(0.5f, -0.5f, 0.5f);
            glVertex3f(0.5f, 0.5f, 0.5f);
            glVertex3f(-0.5f, 0.5f, 0.5f);

            // 后面 (绿色)
            glColor3f(0.0f, 1.0f, 0.0f);
            glVertex3f(-0.5f, -0.5f, -0.5f);
            glVertex3f(0.5f, -0.5f, -0.5f);
            glVertex3f(0.5f, 0.5f, -0.5f);
            glVertex3f(-0.5f, 0.5f, -0.5f);

            // 其他面省略...
        glEnd();
    }
};

int main( int argc, char ** argv )
{
    // 设置 QT_PLUGIN_PATH
    qputenv("QT_PLUGIN_PATH", QDir::toNativeSeparators("../../ThirdParty/qt_msvc_64/plugins").toUtf8());
    for(int i = 0; i < argc; i++) {
        std::cout << "param: " << i << ": " << argv[i] << std::endl;
    }
#if defined (FC_OS_LINUX) || defined(FC_OS_BSD)
    // Make sure to setup the Qt locale system before setting LANG and LC_ALL to C.
    // which is needed to use the system locale settings.
    (void)QLocale::system();
    // See https://forum.freecadweb.org/viewtopic.php?f=18&t=20600
    // See Gui::Application::runApplication()
    putenv("LC_NUMERIC=C");
    putenv("PYTHONPATH=");
#elif defined(FC_OS_MACOSX)
    (void)QLocale::system();
    putenv("PYTHONPATH=");
#elif defined(__MINGW32__)
    const char* mingw_prefix = getenv("MINGW_PREFIX");
    const char* py_home = getenv("PYTHONHOME");
    if (!py_home && mingw_prefix)
        _putenv_s("PYTHONHOME", mingw_prefix);
#else
    _putenv("PYTHONPATH=");
    // https://forum.freecadweb.org/viewtopic.php?f=4&t=18288
    // https://forum.freecadweb.org/viewtopic.php?f=3&t=20515
    const char* fc_py_home = getenv("FC_PYTHONHOME");
    if (fc_py_home)
        _putenv_s("PYTHONHOME", fc_py_home);
    else
        _putenv("PYTHONHOME=");
#endif

#if defined (FC_OS_WIN32)
    // we need to force Coin not to use Freetype in order to find installed fonts on Windows
    // see https://forum.freecadweb.org/viewtopic.php?p=485142#p485016
    _putenv("COIN_FORCE_FREETYPE_OFF=1");

    int argc_ = argc;
    QVector<QByteArray> data;
    QVector<char *> argv_;

    // get the command line arguments as unicode string
    {
        QCoreApplication app(argc, argv);
        QStringList args = app.arguments();
        for (QStringList::iterator it = args.begin(); it != args.end(); ++it) {
            data.push_back(it->toUtf8());
            argv_.push_back(data.back().data());
        }
        argv_.push_back(0); // 0-terminated string
    }
#endif

#if defined(_MSC_VER) && _MSC_VER <= 1800
    // See InterpreterSingleton::init
    Redirection out(stdout), err(stderr), inp(stdin);
#endif

    // Name and Version of the Application
    App::Application::Config()["ExeName"] = "HSSketcher";
    App::Application::Config()["ExeVendor"] = "HSSketcher";
    App::Application::Config()["AppDataSkipVendor"] = "true";
    App::Application::Config()["MaintainerUrl"] = "http://www.freecad.org/wiki/Main_Page";

    // set the banner (for logging and console)
    App::Application::Config()["AppIcon"] = "freecad";
    App::Application::Config()["SplashScreen"] = "freecadsplash";
    App::Application::Config()["AboutImage"] = "freecadabout";
    App::Application::Config()["StartWorkbench"] = "StartWorkbench";
    //App::Application::Config()["HiddenDockWindow"] = "Property editor";
    App::Application::Config()["SplashAlignment" ] = "Bottom|Left";
    App::Application::Config()["SplashTextColor" ] = "#ffffff"; // white
    App::Application::Config()["SplashInfoColor" ] = "#c8c8c8"; // light grey
    App::Application::Config()["SplashInfoPosition" ] = "15.210";

    QGuiApplication::setDesktopFileName(QStringLiteral("org.freecadweb.FreeCAD.desktop"));

    try {
        // Init phase ===========================================================
        // sets the default run mode for FC, starts with gui if not overridden in InitConfig...
        App::Application::Config()["RunMode"] = "Gui";
        App::Application::Config()["Console"] = "0";
        App::Application::Config()["LoggingConsole"] = "1";

        // Inits the Application
#if defined (FC_OS_WIN32)
        App::Application::init(argc_, argv_.data());
#else
        App::Application::init(argc, argv);
#endif
#if defined(_MSC_VER)
        // create a dump file when the application crashes
        std::string dmpfile = App::Application::getUserAppDataDir();
        dmpfile += "crash.dmp";
        // InitMiniDumpWriter(dmpfile);
#endif
        std::map<std::string, std::string>::iterator it = App::Application::Config().find("NavigationStyle");
        if (it != App::Application::Config().end()) {
            ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
            // if not already defined do it now (for the very first start)
            std::string style = hGrp->GetASCII("NavigationStyle", it->second.c_str());
            hGrp->SetASCII("NavigationStyle", style.c_str());
        }

        Gui::Application::initApplication();

        // Only if 'RunMode' is set to 'Gui' do the replacement
        /*if (App::Application::Config()["RunMode"] == "Gui")
            Base::Interpreter().replaceStdOutput();*/
    }
    catch (const Base::UnknownProgramOption& e) {
        QApplication app(argc,argv);
        QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());
        QString msg = QString::fromLatin1(e.what());
        QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");
        QMessageBox::critical(nullptr, appName, s);
        exit(1);
    }
    catch (const Base::ProgramInformation& e) {
        QApplication app(argc,argv);
        QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());
        QString msg = QString::fromUtf8(e.what());
        QString s = QLatin1String("<pre>") + msg + QLatin1String("</pre>");

        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setWindowTitle(appName);
        msgBox.setDetailedText(msg);
        msgBox.setText(s);
        msgBox.exec();
        exit(0);
    }
    catch (const Base::Exception& e) {
        // Popup an own dialog box instead of that one of Windows
        QApplication app(argc,argv);
        QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());
        QString msg;
        /*msg = QObject::tr("While initializing %1 the following exception occurred: '%2'\n\n"
                          "Python is searching for its files in the following directories:\n%3\n\n"
                          "Python version information:\n%4\n")
                          .arg(appName, QString::fromUtf8(e.what()),
                          QString::fromUtf8(Py_EncodeLocale(Py_GetPath(),nullptr)), QString::fromLatin1(Py_GetVersion()));*/
        const char* pythonhome = getenv("PYTHONHOME");
        if (pythonhome) {
            msg += QObject::tr("\nThe environment variable PYTHONHOME is set to '%1'.")
                .arg(QString::fromUtf8(pythonhome));
            msg += QObject::tr("\nSetting this environment variable might cause Python to fail. "
                "Please contact your administrator to unset it on your system.\n\n");
        } else {
            msg += QObject::tr("\nPlease contact the application's support team for more information.\n\n");
        }

        QMessageBox::critical(nullptr, QObject::tr("Initialization of %1 failed").arg(appName), msg);
        exit(100);
    }
    catch (...) {
        // Popup an own dialog box instead of that one of Windows
        QApplication app(argc,argv);
        QString appName = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());
        QString msg = QObject::tr("Unknown runtime error occurred while initializing %1.\n\n"
                                  "Please contact the application's support team for more information.\n\n").arg(appName);
        QMessageBox::critical(nullptr, QObject::tr("Initialization of %1 failed").arg(appName), msg);
        exit(101);
    }

    // Run phase ===========================================================
    Base::RedirectStdOutput stdcout;
    Base::RedirectStdLog    stdclog;
    Base::RedirectStdError  stdcerr;
    std::streambuf* oldcout = std::cout.rdbuf(&stdcout);
    std::streambuf* oldclog = std::clog.rdbuf(&stdclog);
    std::streambuf* oldcerr = std::cerr.rdbuf(&stdcerr);

    try {
        // if console option is set then run in cmd mode
        if (App::Application::Config()["Console"] == "1")
            App::Application::runApplication();
        if (App::Application::Config()["RunMode"] == "Gui" ||
            App::Application::Config()["RunMode"] == "Internal")
            Gui::Application::runApplication();
        else
            App::Application::runApplication();
    }
    /*catch (const Base::SystemExitException& e) {
        exit(e.getExitCode());
    }*/
    catch (const Base::Exception& e) {
        e.ReportException();
        exit(1);
    }
    catch (const std::exception& e) {
        Base::Console().Error("Application unexpectedly terminated: %s\n", e.what());
        exit(1);
    }
    catch (...) {
        Base::Console().Error("Application unexpectedly terminated\n");
        exit(1);
    }

    std::cout.rdbuf(oldcout);
    std::clog.rdbuf(oldclog);
    std::cerr.rdbuf(oldcerr);

    // Destruction phase ===========================================================
    Base::Console().Log("%s terminating...\n",App::Application::Config()["ExeName"].c_str());

    // cleans up
    App::Application::destruct();

    Base::Console().Log("%s completely terminated\n",App::Application::Config()["ExeName"].c_str());

    return 0;
}
